package com.soup.lab.validation.anno;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Calendar;
import java.util.Date;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 用于校验日期查询范围
 * 对象为null，视为校验通过
 * @see DatePair
 */
@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = QueryDatePairValidator.class)
public @interface QueryDatePair {
    /**
     * 日期的格式
     */
    String value() default "yyyy-MM-dd";

    /**
     * 必填条件，默认：不存在就不校验，存在就必须都存在
     */
    Required required() default Required.NONE_OR_BOTH;

    /**
     * 是否在有值且通过后设置日期
     * 默认设置，结束日期会根据 {@link #endDateEditor} 的配置给结束日期追加相应的时间
     *
     * {@link DatePair#setStartDate(Date)}
     * {@link DatePair#setEndDate(Date)}
     */
    boolean setDate() default true;
    /**
     * 结束日期编辑器
     * 默认 +1 天：
     *  对于查询条件为日期的情况，查询时间的结束时间，一般也包含选择时间的全天。
     *  因为这里直接对结束日期增加了一天，所以在进行数据库查询的时候，应该使用 < 判断 而不是 <=
     *
     * {@link DatePair#setEndDate}
     */
    FieldPlusOneEditor endDateEditor() default FieldPlusOneEditor.DAY;

    String message() default "查询时间段错误";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    /**
     * 给指定日期属性额外新增 1
     */
    enum FieldPlusOneEditor {
        YEAR(Calendar.YEAR),
        MONTH(Calendar.MONTH),
        DAY(Calendar.DAY_OF_YEAR),
        HOUR(Calendar.HOUR_OF_DAY),
        MINUTE(Calendar.MINUTE),
        SECOND(Calendar.SECOND),
        // 不修改
        NONE(0);

        private final int value;

        FieldPlusOneEditor(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    enum Required {
        /**
         * 不存在就不校验
         */
        NONE_OR_ANY,
        /**
         * 不存在就不校验
         * 存在就必须都存在
         */
        NONE_OR_BOTH,
        /**
         * 开始时间必须存在
         */
        START,
        /**
         * 结束时间必须存在
         */
        END,
        /**
         * 开始时间和结束时间必须同时存在
         */
        BOTH;
    }


}
